package peopledetectservice

import (
	"fmt"
	"gcc/global"
	"image"
	"io/ioutil"
	"log"
	"net/http"
	"sync"

	"github.com/gin-gonic/gin"
	pd "github.com/paddlepaddle/paddle/paddle/fluid/inference/goapi"
	"gocv.io/x/gocv"
)

func HeartBeatService(c *gin.Context){
	c.Writer.WriteHeader(http.StatusOK)
}

// 图片检测服务，需要加载模型，需要获得照片。
// 先弄简单的，就一个摄像头。
// TODO: 不同地址请求服务，也要完善服务。考虑加载几个模型，怎么加载。
func PDService(c *gin.Context){
	buf, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		log.Printf("peopledetectServer failed, please checkout peopleDetectServe/server.go/ioutil.readall \n")
		c.JSON(http.StatusBadRequest,gin.H{
			"data":false,
		})
	}
	fmt.Println("1.=====================================================")
	defer c.Request.Body.Close()
	mat, err := gocv.IMDecode(buf, gocv.IMReadColor)
	if err != nil {
		log.Printf("gocv.IMDecode() failed, please checkout peopleDetectServe/server.go, \n")
		c.JSON(http.StatusInternalServerError, gin.H{
			"data":false,
		})
	}
	fmt.Println("2.=========================================================")
	_ = normalize(mat)
	fmt.Println("3.===========================================================")
	//isPeople := detect(normalizedPic)
	fmt.Println("4.=========================================================")
	c.JSON(http.StatusOK, gin.H{
		"data":true,
	})
}

//TODO: 这块还是可以优化的，首先考虑生成多个模型进行多协程工作。
func detect(p gocv.Mat)bool{
	// mat转换成[]float32类型
	data, _ := p.DataPtrFloat32()
	config := pd.NewConfig()
	config.SetModel("/home/gccai/distributed-application/peopleDetectService/small_model/model","/home/gccai/distributed-application/peopleDetectService/small_model/para")
	predictor := pd.NewPredictor(config)

	inNames := predictor.GetInputNames()
	inHandler := predictor.GetInputHandle(inNames[0])

	outNames := predictor.GetOutputNames()
	outHandle := predictor.GetOutputHandle(outNames[0])


	inHandler.Reshape([]int32{1,3,320,320})
	inHandler.CopyFromCpu(data)
	predictor.Run()
	outData := make([]float32, numElements(outHandle.Shape()))
	outHandle.CopyToCpu(outData)

	// 根据outData来判断 , 这块需要根据outData来判断。
	return true
}

func numElements(shape []int32) int32 {
	n := int32(1)
	for _, v := range shape {
		n *= v
	}
	return n
}

func normalize(p gocv.Mat) gocv.Mat {
	fmt.Println("1")
	fmt.Println(p.Type())
	pp := gocv.NewMatWithSize(320,320,p.Type())
	fmt.Println("2")
	// 个人感觉这一步有没有都一样
	gocv.Resize(p, &pp, image.Point{320,320},0,0,gocv.InterpolationNearestNeighbor)
	fmt.Println("3")
	bImgs := gocv.Split(pp)
	fmt.Println(bImgs[0].Type())
	fmt.Println("4")
	for i := range bImgs {
		fmt.Println(bImgs[i].Size(), Means[i].Size())
		gocv.Subtract(bImgs[i],Means[i], &bImgs[i])

		gocv.Divide(bImgs[i], Stds[i], &bImgs[i])
	}
	fmt.Println("5")
	res := gocv.NewMatWithSize(320,320,p.Type())
	fmt.Println("6")
	gocv.Merge(bImgs, &res)
	fmt.Println("7")
	r := gocv.BlobFromImage(res,1,image.Point{320,320},gocv.Scalar{0,0,0,0},false,false)
	fmt.Println("7")
	return r

}

func(s *ServiceDependencyMapping) UpdateService(c *gin.Context){
	var p patch

	err := c.ShouldBindJSON(&p)
	if err != nil {
		log.Printf("people detect service: updateService bind data failed. err: %s\n", err.Error())
		c.JSON(http.StatusBadRequest, gin.H{"data":"数据格式出错"})
	}

	s.update(p)
	// return for tell the client the result of sending, if not http.statusOK, you need send the same info again
	c.Writer.WriteHeader(http.StatusOK)
}

var provicer = ServiceDependencyMapping{
	mutex:new(sync.Mutex),
	nameUrlMap:make(map[global.ServiceName][]string),	
}

func (s *ServiceDependencyMapping)update(p patch)  {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	// add mappint to the local servicedependencymapping 
	for _, add := range p.Add{
		if _, ok := provicer.nameUrlMap[add.ServiceName]; !ok {
			provicer.nameUrlMap[add.ServiceName] = make([]string, 0)
		}
		provicer.nameUrlMap[add.ServiceName] = append(provicer.nameUrlMap[add.ServiceName], string(add.ServiceURL))
	}

	// remove mapping from the local
	for _, remove := range p.Removed{
		if providerURLs, ok := provicer.nameUrlMap[remove.ServiceName]; ok {
			for i, providerURL := range providerURLs{
				if global.Address(providerURL) == remove.ServiceURL {
					provicer.nameUrlMap[remove.ServiceName] = append(providerURLs[:i], providerURLs[i+1:]...)
				}
			}
		}
	}
	
}